package com.tuanzi.loan.core.lazy;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;

import com.tuanzi.loan.core.exception.SystemException;
import com.tuanzi.loan.core.vo.IdentityResponse;
import com.tuanzi.loan.core.vo.PageSearcher;

import lombok.extern.slf4j.Slf4j;

/**
 * @author Ray 2017/09/21
 */
@Slf4j
public abstract class BaseLazyDataModel<K, T extends IdentityResponse> extends LazyDataModel<T> {

	private static final long serialVersionUID = 9143007553234885156L;

	protected final K searchRequest;

	public BaseLazyDataModel(K k) {
		searchRequest = k;
	}

	@Override
	public T getRowData() {
		return super.getRowData();
	}

	@Override
	public final List<T> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {

		PageRequest pageRequest = null;
		String mappedSortField = getMappedSortField(sortField);
		if (StringUtils.isNotBlank(mappedSortField)) {
			pageRequest = new PageRequest(first / pageSize, pageSize, sortOrder == SortOrder.ASCENDING ? Sort.Direction.ASC : Sort.Direction.DESC, mappedSortField);
		} else {
			pageRequest = new PageRequest(first / pageSize, pageSize);
		}

		try {
			BeanUtils.populate(searchRequest, filters);
		} catch (IllegalAccessException | InvocationTargetException e) {
			log.error(e.getMessage(), e);
		}

		log.debug("search vo : {}, values : {} ", searchRequest.getClass().getSimpleName(), ToStringBuilder.reflectionToString(searchRequest));

		PageSearcher<K> pageSearcher = new PageSearcher<K>(searchRequest, pageRequest);
		Page<T> result = doLoad(pageSearcher);
		this.setRowCount((int) result.getTotalElements());
		return result.getContent();
	}

	@SuppressWarnings("unchecked")
	private String getMappedSortField(String sortField) {
		if (StringUtils.isBlank(sortField)) {
			return StringUtils.EMPTY;
		}
		try {
			Class<?> responseClass = null;
			Type t = getClass().getGenericSuperclass();
			if (t instanceof ParameterizedType) {
				Type[] p = ((ParameterizedType) t).getActualTypeArguments();
				responseClass = (Class<T>) p[1];
			}
			Field field = responseClass.getDeclaredField(sortField);
			com.tuanzi.loan.core.entity.Sort sort = field.getAnnotation(com.tuanzi.loan.core.entity.Sort.class);
			return sort.value();
		} catch (Exception e) {
			log.warn("排序字段 : " + sortField + " 没找到对应的sort field", e);
			return StringUtils.EMPTY;
		}
	}

	@Override
	public Object getRowKey(T object) {
		return object.getId();
	}

	@SuppressWarnings("unchecked")
	@Override
	public T getRowData(String rowKey) {
		List<T> data = (List<T>) getWrappedData();
//		return data.stream().filter(x -> x.getId().toString().equals(rowKey)).findFirst().orElseThrow(() -> new SystemException("rowKey:" + rowKey + " 没法找到对应记录"));
		return data.stream().filter(x -> x.getId().toString().equals(rowKey)).findFirst().orElse(null);
	}

	public T getRowId(Integer index) {
		List<T> data = (List<T>) getWrappedData();
		if (data.size()<index) new SystemException("Index:" + index + " 没法找到对应记录");
		return data.get(index);
	}


	protected abstract Page<T> doLoad(PageSearcher<K> pageSearcher);
}
